﻿using System;
using System.Collections.Concurrent;

namespace RAP.Framework.Libary.Utils.Factory
{
  /// <summary>
  /// 工厂基类
  /// </summary>
  public class FactoryBase<TElement> : ConcurrentDictionary<string, object>, IFactory<TElement>
  {
    /// <summary>
    /// 工厂变更事件
    /// </summary>
    public event Action OnChange;

    protected virtual void TriggerChangeEvent( )
    {
      this.OnChange?.Invoke();
    }

    /// <summary>
    /// 获取或设置指定key的成员对象
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public virtual new TElement this[ string key ]
    {
      get
      {
        this.TryGetValue( key, out object element );
        if ( element == null )
        {
          return default( TElement );
        }
        return ( TElement )element;
      }
      set
      {
        this[ key ] = value;
        this.TriggerChangeEvent();
      }
    }

    public virtual void Initialize( ) { }

    /// <summary>
    /// 注册实例
    /// </summary>
    /// <param name="key"></param>
    /// <param name="element"></param>
    /// <returns></returns>
    public virtual TElement Register( string key, TElement element )
    {
      this.Add( key, element );
      this.TriggerChangeEvent();
      return element;
    }

    /// <summary>
    /// 注册函数
    /// </summary>
    /// <param name="key"></param>
    /// <param name="func"></param>
    /// <returns></returns>
    public virtual Func<TElement> Register( string key, Func<TElement> func )
    {
      this.Add( key, func );
      this.TriggerChangeEvent();
      return func;
    }

    /// <summary>
    /// 注册类型
    /// </summary>
    /// <param name="key"></param>
    /// <param name="elementType"></param>
    /// <returns></returns>
    public virtual Type Register( string key, Type elementType )
    {
      this.Add( key, elementType );
      this.TriggerChangeEvent();
      return elementType;
    }

    /// <summary>
    /// 注册类型名称
    /// </summary>
    /// <param name="key"></param>
    /// <param name="elementTypeName"></param>
    /// <returns></returns>
    public virtual string Register( string key, string elementTypeName )
    {
      this.Add( key, elementTypeName );
      this.TriggerChangeEvent();
      return elementTypeName;
    }

    /// <summary>
    /// 重写基类的TryGetValue实现，获取字典内部存储的成员对象实例
    /// </summary>
    /// <param name="key"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    public virtual new bool TryGetValue( string key, out object value )
    {
      var r = base.TryGetValue( key, out object val );
      value = null;
      if ( r )
      {
        if ( val is Func<TElement> )
        {
          value = ( val as Func<TElement> )();
        }
        else if ( val is Type )
        {
          value = ( val as Type ).CreateInstance<TElement>();
        }
        else if ( val is TElement )
        {
          value = ( TElement )val;
        }
        else if ( val is string )
        {
          value = val.ToString().CreateInstance<TElement>();
        }
        else
        {
          value = val;
        }
      }
      return r;
    }

    /// <summary>
    /// 移除指定key的成员定义
    /// </summary>
    /// <param name="key"></param>
    public virtual void Remove( string key )
    {
      this.TryRemove( key, out object removedItem );
      this.TriggerChangeEvent();
    }

    /// <summary>
    /// 
    /// </summary>
    public new void Clear( )
    {
      base.Clear();
      this.TriggerChangeEvent();
    }
  }
}
